import {mergeI18nFromRoutes} from '@/utils/i18n'
import Router from 'vue-router'
import deepMerge from 'deepmerge'
import basicOptions from '@/router/async/config.async'
import {ROUTES} from '@/services/api';
import {request, METHOD} from '@/utils/request';
import {makeTree} from '@/utils/util';

//应用配置
let appOptions = {
        router: undefined,
        i18n: undefined,
        store: undefined
}

/**
 * 设置应用配置
 * @param options
 */
function setAppOptions(options) {
        const {router, store, i18n} = options
        appOptions.router = router
        appOptions.store = store
        appOptions.i18n = i18n
}

/**
 * 根据 路由配置 和 路由组件注册 解析路由
 * @param routesConfig 路由配置
 * @param routerMap 本地路由组件注册配置
 */
function parseRoutes(routesConfig, routerMap) {
        let routes = [];
        routesConfig.forEach(item => {
                // 获取注册在 routerMap 中的 router，初始化 routeCfg
                let router = undefined, routeCfg = {}
                if (typeof item === 'string') {
                        router = routerMap[item]
                        routeCfg = {path: (router && router.path) || item, router: item}
                } else if (typeof item === 'object') {
                        router = routerMap[item.router]
                        routeCfg = item
                }
                if (!router) {
                        console.warn(`can't find register for router ${routeCfg.router}, please register it in advance.`)
                        router = typeof item === 'string' ? {path: item, name: item} : item
                }
                // 从 router 和 routeCfg 解析路由
                const meta = {
                        authority: router.authority,
                        icon: router.icon,
                        page: router.page,
                        link: router.link,
                        params: router.params,
                        query: router.query,
                        ...router.meta
                }
                const cfgMeta = {
                        authority: routeCfg.authority,
                        icon: routeCfg.icon,
                        page: routeCfg.page,
                        link: routeCfg.link,
                        params: routeCfg.params,
                        query: routeCfg.query,
                        ...routeCfg.meta
                }
                Object.keys(cfgMeta).forEach(key => {
                        if (cfgMeta[key] === undefined || cfgMeta[key] === null || cfgMeta[key] === '') {
                                delete cfgMeta[key]
                        }
                })
                Object.assign(meta, cfgMeta)
                const route = {
                        path: routeCfg.path || router.path || routeCfg.router,
                        name: routeCfg.name || router.name,
                        component: router.component,
                        redirect: routeCfg.redirect || router.redirect,
                        meta: {...meta, authority: meta.authority || '*'}
                }
                if (routeCfg.invisible || router.invisible) {
                        route.meta.invisible = true
                }
                if (routeCfg.children && routeCfg.children.length > 0) {
                        route.children = parseRoutes(routeCfg.children, routerMap)
                }
                routes.push(route)
        })
        return routes
}

/**
 * 加载路由
 * @param routesConfig 路由配置
 * @param routerMap 本地路由组件注册配置
 */
function loadRoutes(routesConfig, routerMap) {
        //兼容 0.6.1 以下版本
        /*************** 兼容 version < v0.6.1 *****************/
        if (arguments.length > 0) {
                const arg0 = arguments[0]
                if (arg0.router || arg0.i18n || arg0.store) {
                        routesConfig = arguments[1]
                        console.error('the usage of signature loadRoutes({router, store, i18n}, routesConfig) is out of date, please use the new signature: loadRoutes(routesConfig).')
                        console.error('方法签名 loadRoutes({router, store, i18n}, routesConfig) 的用法已过时, 请使用新的方法签名 loadRoutes(routesConfig)。')
                }
        }
        /*************** 兼容 version < v0.6.1 *****************/
                // 应用配置
        const {router, store, i18n} = appOptions
        // 如果 routesConfig 有值，则更新到本地，否则从本地获取
        if (routesConfig) {
                store.commit('account/setRoutesConfig', routesConfig)
        } else {
                routesConfig = store.getters['account/routesConfig']
        }
        // 如果开启了异步路由，则加载异步路由配置
        const asyncRoutes = store.state.setting.asyncRoutes
        if (asyncRoutes) {
                if (routesConfig && routesConfig.length > 0 && routerMap) {
                        const routes = parseRoutes(routesConfig, routerMap);
                        const finalRoutes = mergeRoutes(basicOptions.routes, routes);
                        formatRoutes(finalRoutes);
                        router.options = {...router.options, routes: finalRoutes};
                        router.matcher = new Router({...router.options, routes: []}).matcher;
                        router.addRoutes(finalRoutes);
                }
        }
        // 提取路由国际化数据
        mergeI18nFromRoutes(i18n, router.options.routes)
        // 初始化Admin后台菜单数据
        const rootRoute = router.options.routes.find(item => item.path === '/');
        const menuRoutes = rootRoute && rootRoute.children;
        if (menuRoutes) {
                store.commit('setting/setMenuData', menuRoutes)
        }
}

/**
 * 合并路由
 * @param target {Route[]}
 * @param source {Route[]}
 * @returns {Route[]}
 */
function mergeRoutes(target, source) {
        const routesMap = {}
        target.forEach(item => routesMap[item.path] = item)
        source.forEach(item => routesMap[item.path] = item)
        return Object.values(routesMap)
}

/**
 * 深度合并路由
 * @param target {Route[]}
 * @param source {Route[]}
 * @returns {Route[]}
 */
function deepMergeRoutes(target, source) {
        // 映射路由数组
        const mapRoutes = routes => {
                const routesMap = {}
                routes.forEach(item => {
                        routesMap[item.path] = {
                                ...item,
                                children: item.children ? mapRoutes(item.children) : undefined
                        }
                })
                return routesMap
        }
        const tarMap = mapRoutes(target)
        const srcMap = mapRoutes(source)

        // 合并路由
        const merge = deepMerge(tarMap, srcMap)

        // 转换为 routes 数组
        const parseRoutesMap = routesMap => {
                return Object.values(routesMap).map(item => {
                        if (item.children) {
                                item.children = parseRoutesMap(item.children)
                        } else {
                                delete item.children
                        }
                        return item
                })
        }
        return parseRoutesMap(merge)
}

/**
 * 格式化路由
 * @param routes 路由配置
 */
function formatRoutes(routes) {
        routes.forEach(route => {
                const {path} = route
                if (!path.startsWith('/') && path !== '*') {
                        route.path = '/' + path
                }
        })
        formatAuthority(routes)
}

/**
 * 格式化路由的权限配置
 * @param routes 路由
 * @param pAuthorities 父级路由权限配置集合
 */
function formatAuthority(routes, pAuthorities = []) {
        routes.forEach(route => {
                const meta = route.meta
                const defaultAuthority = pAuthorities[pAuthorities.length - 1] || {permission: '*'}
                if (meta) {
                        let authority = {}
                        if (!meta.authority) {
                                authority = defaultAuthority
                        } else if (typeof meta.authority === 'string') {
                                authority.permission = meta.authority
                        } else if (typeof meta.authority === 'object') {
                                authority = meta.authority
                                const {role} = authority
                                if (typeof role === 'string') {
                                        authority.role = [role]
                                }
                                if (!authority.permission && !authority.role) {
                                        authority = defaultAuthority
                                }
                        }
                        meta.authority = authority
                } else {
                        const authority = defaultAuthority
                        route.meta = {authority}
                }
                route.meta.pAuthorities = pAuthorities
                if (route.children) {
                        formatAuthority(route.children, [...pAuthorities, route.meta.authority])
                }
        })
}

/**
 * 从路由 path 解析 i18n key
 * @param path
 * @returns {*}
 */
function getI18nKey(path) {
        const keys = path.split('/').filter(item => !item.startsWith(':') && item != '')
        keys.push('name')
        return keys.join('.')
}

/**
 * 加载导航守卫
 * @param guards
 * @param options
 */
function loadGuards(guards, options) {
        const {beforeEach, afterEach} = guards
        const {router} = options
        beforeEach.forEach(guard => {
                if (guard && typeof guard === 'function') {
                        router.beforeEach((to, from, next) => guard(to, from, next, options))
                }
        })
        afterEach.forEach(guard => {
                if (guard && typeof guard === 'function') {
                        router.afterEach((to, from) => guard(to, from, options))
                }
        })
}

/**
 * 加载个人登录后的路由
 */
function loadPersonalAfterLoginRoutes(callback, errorCallback) {
        // 视图组件
        const view = {
                tabs: () => import('@/layouts/tabs'),
                blank: () => import('@/layouts/BlankView'),
                page: () => import('@/layouts/PageView')
        }
        var routerMap = require('@/router/async/router.map').default;
        var routesConfig = [
                'login',
                {
                        router: 'exp404',
                        path: '*',
                        name: '404'
                },
                {
                        router: 'exp403',
                        path: '/403',
                        name: '403'
                },
                {
                        router: 'exp500',
                        path: '/500',
                        name: '500'
                },
                {
                        router: 'root',
                        children: [
                                {
                                        router: 'dashboard',
                                        children: ['workplace', 'analysis'],
                                }
                        ],
                }
        ];
        request(ROUTES, METHOD.GET).then(function (result) {
                var arrMenu = result.data.data.menu;
                arrMenu.forEach(function (v) {
                        var objTemp = {
                                path: v.route,
                                name: v.name,
                                component: (v.path === '') ? view.page : () => import('@/pages' + v.path),
                                meta: {}
                        };
                        if (v.path) {
                                objTemp.meta.authority = v.powerDiscern;
                        }
                        if (v.icon) {
                                objTemp.meta.icon = v.icon;
                        }
                        if (v.urlParams) {
                                objTemp.meta.query = JSON.parse(v.urlParams);
                        }
                        if (v.pathParams) {
                                objTemp.meta.params = JSON.parse(v.pathParams);
                        }
                        routerMap[v.powerDiscern] = objTemp;
                });
                var arrMenuTree = makeTree(arrMenu, 'menuId');
                routesConfig[4].children = routesConfig[4].children.concat(getRoutesConfig(arrMenuTree));
                const {store} = appOptions
                store.commit('account/setPermissions', result.data.data.permissions)
                loadRoutes(routesConfig, routerMap);
                if (callback) callback(routesConfig, routerMap, result);
        }).catch(function (error) {
                if (errorCallback) errorCallback(error);
        });
}

/**
 * 获取路由配置
 * @param menuList
 * @param parent
 * @returns {*[]}
 */
function getRoutesConfig(menuList = [], parent = []) {
        for (var i = 0; i < menuList.length; i++) {
                var route = {};
                if (menuList[i].children && menuList[i].children.length > 0) {
                        route = {
                                router: menuList[i].powerDiscern,
                                children: []
                        };
                        getRoutesConfig(menuList[i].children, route['children']);
                }else{
                        route = menuList[i].powerDiscern;
                }
                if (JSON.stringify(route) !== '{}') {
                        parent.push(route);
                }
        }
        return parent;
}

export {
        parseRoutes,
        loadRoutes,
        formatAuthority,
        getI18nKey,
        loadGuards,
        deepMergeRoutes,
        formatRoutes,
        setAppOptions,
        loadPersonalAfterLoginRoutes
}
